<template>
	<div
		:class="classes()"
		:style="style"
		@click="clickFn"
		@mouseenter="hover=true"
		@mouseleave="hover=false"
	>
		<slot
			v-if="prefixIcon||$slots.prefix"
			name="prefix"
			v-bind="slotScope()"
		>
			<Icon
				:name="prefixIcon"
				class="pf-Input_icon pf--prefix"
				@click.stop="clickPrefixIconFn"
			/>
		</slot>
		<div :class="wrapClasses()">
			<input
				ref="inputRef"
				v-bind="$attrs"
				:type="inputRealType()"
				:value="modelValue"
				:disabled="disabled"
				:readonly="readonly"
				:maxlength="maxlength"
				class="pf-Input_input"
				@input="inputFn"
				@focus="focusFn"
				@blur="blurFn"
			>
			<template v-if="!modelValue">{{placeholder}}</template>
		</div>
		<Icon
			v-if="showClearIcon()"
			name="bi-x-circle-fill"
			class="pf-Input_clear"
			@click.stop="withFocus(clear)"
		/>
		<Icon
			v-if="showEyeIcon()"
			:name="showPassword?'bi-eye-slash-fill':'bi-eye-fill'"
			class="pf-Input_password"
			@click.stop="maskPasswordFn"
		/>
		<slot
			v-if="suffixIcon||$slots.suffix"
			name="suffix"
			v-bind="slotScope()"
		>
			<Icon
				:name="suffixIcon"
				class="pf-Input_icon pf--suffix"
				@click.stop="clickSuffixIconFn"
			/>
		</slot>
	</div>
</template>

<script setup lang="ts">
import type {
	InputType,
	InputShape,
} from './type';
import {
	shallowRef,
	nextTick,
} from 'vue';
import Icon from '../Icon/Icon';
import useAutoFocus from '../../../composables/useAutoFocus';
/**
 * 输入框组件
 * @author 唐国雄
 * @date 2022/11/7
 * 属性----------------------
 * v-model			当前值
 * :type			类型
 * :shape			形状
 * :placeholder		占位文本
 * :prefix-icon		前缀图标
 * :suffix-icon		后缀图标
 * :password		密码显示切换
 * :disabled		禁用状态
 * :readonly		只读状态
 * :clearable		可清空
 * :autofocus		自动聚焦
 * :maxlength		最大输入长度
 * 事件----------------------
 * @update:modelValue	值变化
 * @clear				点击清空
 * @click				点击事件
 * @click-prefix-icon	前缀图标, 点击事件
 * @click-suffix-icon	后缀图标, 点击事件
 * 插槽----------------------
 * #prefix			前缀插槽
 * #suffix			后缀插槽
 * 方法----------------------
 * getInfo()		获取所有信息
 * clear()			清空
 * maskPassword()	显示/隐藏密码
 */
const emit=defineEmits<{
	(e:'update:modelValue',val:string):void;
	(e:'clear'):void;
	(e:'click'):void;
	(e:'click-prefix-icon'):void;
	(e:'click-suffix-icon'):void;
}>();
const props=withDefaults(defineProps<{
	class?:any;
	style?:any;
	modelValue:string;
	type?:InputType;
	shape?:InputShape;
	placeholder?:string;
	prefixIcon?:string;
	suffixIcon?:string;
	password?:boolean;
	disabled?:boolean;
	readonly?:boolean;
	clearable?:boolean;
	autofocus?:boolean;
	maxlength?:number;
}>(),{
	type:'text',
	password:true,
});
const inputRef=shallowRef<HTMLInputElement>(null);
const focus=shallowRef(false);
const hover=shallowRef(false);
const showPassword=shallowRef(false);
//自动聚焦
useAutoFocus(() => props.autofocus,inputRef,focus);
//region 输入框类型
const inputRealType=(() => {
	return props.type==='password'&&!(props.password&&showPassword.value)
		?'password'
		:'text';
});
//endregion
//region 是否显示, 清空按钮
const showClearIcon=(():boolean => {
	return props.clearable&&hover.value&&props.modelValue!==''&&!(props.disabled||props.readonly);
});
//endregion
//region 是否显示, 眼睛按钮
const showEyeIcon=(():boolean => {
	return props.password&&props.modelValue&&props.type==='password';
});
//endregion
//region 类名
const classes=() => {
	return 'pf-Input'+
		(props.shape?` pf--shape-${props.shape}`:'')+
		(focus.value?' pf--focus':'')+
		(props.disabled?' pf--disabled':props.readonly?' pf--readonly':'')+
		(props.class?' '+props.class:'');
};
const wrapClasses=() => {
	return 'pf-Input_inputWrap'+
		(props.modelValue?'':' pf--empty');
};
//endregion
//region 插槽作用域
const slotScope=() => {
	return {
		showPassword:showPassword.value,
		withFocus,
		clear,
		maskPassword,
	};
};
//endregion
//region 聚焦逻辑
function withFocus(after?:() => void):boolean{
	if(props.disabled){
		return;
	}
	after&&after();
	if(!focus.value){
		nextTick(() => {
			inputRef.value.focus();
		});
	}
}
//endregion
//region 清空操作
function clear():void{
	emit('clear');
	if(props.modelValue!==''){
		emit('update:modelValue','');
	}
}
//endregion
//region 隐藏/显示密码
function maskPassword():void{
	showPassword.value=!showPassword.value;
}
function maskPasswordFn(){
	maskPassword();
	withFocus();
}
//endregion
//region 点击事件
function clickFn(){
	withFocus(() => {
		emit('click');
	});
}
function clickPrefixIconFn(){
	withFocus(() => {
		emit('click-prefix-icon');
	});
}
function clickSuffixIconFn(){
	withFocus(() => {
		emit('click-suffix-icon');
	});
}
//endregion
//region 值变化处理器
function inputFn(e:InputEvent){
	const val=(e.target as HTMLInputElement).value;
	if(props.modelValue!==val){
		emit('update:modelValue',val);
	}
}
//endregion
//region 聚焦,失焦处理器
function focusFn(){
	focus.value=true;
}
function blurFn(){
	focus.value=false;
}
//endregion
//region 导出的内容
defineExpose({
	getInfo(){
		return {
			showPassword:showPassword.value,
			showClearIcon:showClearIcon(),
			showEyeIcon:showEyeIcon(),
		};
	},
	clear,
	maskPassword,
});
//endregion
</script>

<script lang="ts">
export default {
	inheritAttrs:false,
};
</script>